iT邦幫忙

2025 iThome 鐵人賽

DAY 23
0
DevOps

30 天 Terraform 學習筆記:從零開始的 IaC 實戰系列 第 23

Day 23 - Provisioners 與 External Data:Terraform 與外部世界的橋樑

  • 分享至 

  • xImage
  •  

昨天我們聊到 Functions 與 Locals,學會了怎麼讓程式碼更乾淨、好維護。

今天要來看看 Terraform 的另一個面向:怎麼跟外部世界互動。
在實務上,我們有時候需要 Terraform 做一些「額外動作」,或是讀取「Terraform 本身沒辦法直接拿到的資訊」。這時候就會用到 ProvisionersExternal Data Source

什麼是 Provisioners?

Provisioner 可以想像成「附加動作」:當 Terraform 建立或刪除資源時,額外執行一段 script 或命令。

常見的 Provisioner 類型

  • local-exec → 在 本機 執行命令。
  • remote-exec → SSH 連到遠端 VM 執行命令。

舉個例子:建立 VM 後發 Chat 通知

有時候如果需要在完成某些事情時能推播讓夥伴們知道就可以這麼做:

resource "google_compute_instance" "vm" {
  name         = "demo-vm"
  machine_type = "e2-medium"
  zone         = "us-central1-a"

  boot_disk {
    initialize_params {
      image = "debian-cloud/debian-11"
    }
  }

  provisioner "local-exec" {
    command = <<EOT
      curl -X POST -H 'Content-Type: application/json' \
      -d '{"text":"VM 建立完成啦!(來自 Terraform)"}' \
      "https://chat.googleapis.com/v1/spaces/AAA.../messages?key=xxx&token=yyy"
    EOT
  }
}

這樣 Terraform 在成功建立 VM 後,就會自動呼叫 Google Chat。

Provisioner 的生命周期(lifecycle hooks)

Provisioner 不只可以在「建立後」執行,還有其他情境:

  • create(預設):資源建立完成後執行
  • destroy:資源刪除前執行
  • create_before_destroy:搭配 lifecycle,先建立新資源,再刪除舊的

舉個例子:刪除 VM 前寄出警告信

provisioner "local-exec" {
  when    = destroy
  command = "echo 'VM ${self.name} 即將被刪除' | mail -s '警告通知' admin@example.com"
}

使用 Provisioner 的最佳實務

很多人會拿它來「初始化 VM」裝軟體(例如安裝 Nginx),但這樣會讓 Terraform 的宣告式基礎架構變得太依賴命令式腳本,後續難以維護。

會比較建議用在:

  • 初始化 VM → 用 Cloud-init / Metadata Startup Script
  • 大量配置 → 用 Config Management 工具
  • Provisioner 適合用在最後一個步驟,例如:
    • 發通知
    • 註冊外部系統
    • Terraform 沒有 Provider 的小補充

External Data Source:擴充版 Data Source

還記得我們前面文章中有講過 Data Source 嗎?例如,查詢某個 GCP 區域有哪些可用的 Zone:

data "google_compute_zones" "available" {
  region = "asia-east1"
}

output "zones" {
  value = data.google_compute_zones.available.names
}

這樣 Terraform 就能動態抓到 asia-east1-a/b/c 而不是手動硬編碼。

但如果今天 Terraform 沒有內建的 Data Source 可以查呢?這時候就要用 External Data Source!它能讓 Terraform 執行一個外部程式(Python、Shell、Node.js…),並把輸出的 JSON 帶回來。

範例 1:查詢外部版本號

data "external" "app_version" {
  program = ["python3", "${path.module}/scripts/get_version.py"]
}

output "version" {
  value = data.external.app_version.result["version"]
}

scripts/get_version.py

#!/usr/bin/env python3
import json
print(json.dumps({"version": "1.2.3"}))

Terraform 會執行這支 Python,並把輸出的 JSON 存到 data.external.app_version.result

範例 2:呼叫 API 拿金鑰

也很多人會用它來串接外部 API:

data "external" "apikey" {
  program = ["bash", "${path.module}/scripts/fetch_key.sh"]
}

output "api_key" {
  value = data.external.apikey.result["key"]
}

scripts/fetch_key.sh

#!/usr/bin/env bash
curl -s "https://example.com/get-key" | jq -c

這樣 Terraform 就能把外部 API 回傳的金鑰直接用在資源建立中。

Data Source vs External Data Source

特性 Data Source(一般) External Data Source
來源 Provider 官方提供(AWS, GCP, Azure) 任何外部程式(script / API)
資料格式 Provider 定義好 必須是 JSON
適合場合 查詢雲端現有資源資訊 Terraform 沒辦法直接取得的資訊

可以理解成:

  • Data Source → 官方提供的「查資料捷徑」
  • External Data Source → 自己 DIY 的「查資料外掛」

總結一下

今天認識了 Terraform 裡的兩個「外掛工具」:ProvisionerExternal Data Source

前者適合在資源建立後做一些額外動作,例如發送通知;後者則能讓 Terraform 向外部程式或 API 查詢資訊,補足 Provider 沒支援的情境。

不過,這兩個工具都不適合當核心依賴。Provisioner 容易造成狀態不一致,External Data Source 也不該過度使用。最好的做法,是把它們當成輔助功能:需要時加上去,讓整個流程更靈活,但不要讓專案過度依賴。


上一篇
Day 22 - Terraform Functions 與 Local Values
系列文
30 天 Terraform 學習筆記:從零開始的 IaC 實戰23
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言